package com.lsh.oms.core.service.business.impl;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import com.lsh.base.common.model.CommonResult;
import com.lsh.oms.api.model.status.CancelOrderDto;
import com.lsh.oms.core.constant.ReturnCode;
import com.lsh.oms.core.enums.OrderOperateType;
import com.lsh.oms.core.enums.OrderStatus;
import com.lsh.oms.core.exception.BusinessException;
import com.lsh.oms.core.model.order.OrderHead;
import com.lsh.oms.core.model.order.OrderHeadExt;
import com.lsh.oms.core.proxy.handler.AsyncTaskHandler;
import com.lsh.oms.core.proxy.handler.OrderConcurrentHandler;
import com.lsh.oms.core.proxy.service.AtpProxy;
import com.lsh.oms.core.proxy.service.EsProxy;
import com.lsh.oms.core.service.business.CancelOrderService;
import com.lsh.oms.core.service.order.OrderQueryService;
import com.lsh.oms.core.service.order.OrderUpdateService;
import com.lsh.oms.core.service.payment.PaymentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author panxudong
 * @date 17/3/23
 */
public abstract class AbstractCancelOrderService implements CancelOrderService {

    private static final Logger logger = LoggerFactory.getLogger(AbstractCancelOrderService.class);

    @Autowired
    private OrderQueryService orderQueryService;

    @Autowired
    private OrderUpdateService orderUpdateService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private AtpProxy atpProxy;

    @Autowired
    private EsProxy esProxy;


    @Transactional
    @Override
    public CommonResult cancelOrder4split(CancelOrderDto cancelOrderDto, String logSign, Long venderId) throws BusinessException {
        long startTime = this.getStartTime();
        String logPrefix = this.getLogPrefix(logSign);
        logger.info(this.getLogContent(logPrefix, startTime, "Start"));

        CommonResult<Object> commonResult;
        //检查参数
        if (!this.checkParams(cancelOrderDto)) {
            String message = "cancelOrder4split 参数不能为空,Params:" + JSON.toJSONString(cancelOrderDto);
            logger.error(this.getLogContent(logPrefix, startTime, message));
            commonResult = this.createResult(ReturnCode.REQUEST_PARAMS_IS_NULL, "参数不能为空.");
            return commonResult;
        }

        //加载订单
        Long orderCode = cancelOrderDto.getOrderCode();
        OrderHead orderHead = this.findOrderHead(orderCode);
        if (orderHead == null) {
            String message = "cancelOrder4split 订单号无对应订单,OrderCode:" + orderCode;
            logger.error(this.getLogContent(logPrefix, startTime, message));
            commonResult = this.createResult(ReturnCode.FIND_ORDER_IS_NULL, "用户订单号不匹配.");
            return commonResult;
        }
        // 20180906
        int status = orderHead.getOrderStatus().intValue();
        int valid = orderHead.getValid();
        if (!cancelOrderDto.getMisCodeCancelFalg() && status == OrderStatus.ORDER_SPLIT_CHECK.getIndex()) {

            String message = " cancelOrder4split 当前状态不允许取消,OrderStatus:" + status + ",valid:" + valid;
            logger.error(this.getLogContent(logPrefix, startTime, message));
            commonResult = this.createResult(ReturnCode.ORDER_STATUS_ERROR, "当前订单不允许取消，请核实!");
            return commonResult;
        }

        OrderHead parentOrderHead = null;
        logger.info(" 取消订单信息 {}", JSON.toJSONString(orderHead));
        if (!orderHead.getParentOrderCode().equals(0L)) {
            parentOrderHead = this.findParentOrderHead(orderHead.getParentOrderCode());
        }

        logger.info(" 取消订单 父单信息 {}", JSON.toJSONString(parentOrderHead));
        //检查状态
        int region = orderHead.getRegionCode().intValue();
        if (!this.checkStatus(status, region)) {
            String message = " cancelOrder4split 当前状态不允许取消,OrderStatus:" + status + ",Region:" + region;
            logger.error(this.getLogContent(logPrefix, startTime, message));
            commonResult = this.createResult(ReturnCode.ORDER_STATUS_ERROR, "当前订单不允许取消，请核实!");
            return commonResult;
        }

        CommonResult<Boolean> cancelResult = this.cancel(orderHead, logSign);
        if (!cancelResult.getData()) {
            String message = " cancelOrder4split 订单取消失败,OrderCode:" + orderCode;
            logger.error(this.getLogContent(logPrefix, startTime, message));

            if (this.isForceCancel(orderHead, logSign)) {
                commonResult = this.createResult(ReturnCode.ORDER_SUPPORT_FORCE_CANCEL, " cancelOrder4split 订单取消失败.");
            } else {
                if (!StringUtils.isBlank(cancelResult.getMessage())) {
                    commonResult = this.createResult(ReturnCode.REQUEST_FAIL, cancelResult.getMessage());
                } else {
                    commonResult = this.createResult(ReturnCode.REQUEST_FAIL, "订单取消失败.");
                }
            }

            return commonResult;
        }

        boolean isFulfill = this.isFulfill(status);
        if (parentOrderHead != null) {
            //恢复库存
            boolean restoreAtp = this.atpProxy.restore(parentOrderHead.getOrderCode(), orderHead.getDetails(), isFulfill, logSign, orderHead.getVenderId());
            if (!restoreAtp) {
                String message = "parentOrderHead cancelOrder4split 请求ATP恢复库存失败,OrderCode:" + orderCode;
                logger.error(this.getLogContent(logPrefix, startTime, message));
                commonResult = this.createResult(ReturnCode.REQUEST_ATP_ERROR_CANCEL_ORDER, " cancelOrder4split 请求ATP恢复库存失败.");
                return commonResult;
            }
        } else {
            boolean restoreAtp = this.atpProxy.restore(orderCode, isFulfill, logSign, orderHead.getVenderId());
            if (!restoreAtp) {
                String message = "order cancelOrder4split 请求ATP恢复库存失败,OrderCode:" + orderCode;
                logger.error(this.getLogContent(logPrefix, startTime, message));
                commonResult = this.createResult(ReturnCode.REQUEST_ATP_ERROR_CANCEL_ORDER, " cancelOrder4split 请求ATP恢复库存失败.");
                return commonResult;
            }
        }

        //更新数据库
        try {
            OrderOperateType orderOperateType = this.getOperateType();
            Integer number = this.orderUpdateService.updateOrderStatus(orderCode, null, orderOperateType, venderId);
            if (number <= 0) {
                String message = "更新数据库失败,OrderCode:" + orderCode;
                logger.error(this.getLogContent(logPrefix, startTime, message));
                commonResult = this.createResult(ReturnCode.UPDATE_FAIL, "订单取消失败,订单状态发生改变.");
                return commonResult;
            } else {
                this.updateHeadExt(orderCode, cancelOrderDto);
            }
        } catch (Exception e) {
            String message = "订单取消失败,OrderCode:" + orderCode;
            logger.error(this.getLogContent(logPrefix, startTime, message));
            logger.error(e.getMessage(), e);
            commonResult = this.createResult(ReturnCode.UPDATE_FAIL, "订单取消失败,更新数据库失败");
            return commonResult;
        }

        try {
            if (parentOrderHead != null) {
                // 判断是否所有子单都取消了
                List<OrderHead> orderHeadList = orderQueryService.findByParentOrderCode(parentOrderHead.getOrderCode(), false, false);
                if (CollectionUtils.isEmpty(orderHeadList)) {
                    throw new BusinessException(ReturnCode.FIND_ORDER_IS_NULL, parentOrderHead.getOrderCode() + " : 订单对应的子单不存在");
                }
                Boolean allCancel = false;
                for (OrderHead head : orderHeadList) {
                    if (head.getOrderStatus().compareTo(OrderStatus.ORDER_CANCEL_CUSTOMERSERVICE.getIndex()) >= 0) {
                        allCancel = true;
                    } else {
                        allCancel = false;
                        break;
                    }
                }
                if (allCancel) {
                    paymentService.orderCancelNotifyShop(Collections.singletonList(parentOrderHead.getOrderCode()), logSign, parentOrderHead.getVenderId());
                }
            }
        } catch (BusinessException e) {
            String message = "订单取消,通知商城失败,OrderCode:" + orderCode;
            logger.error(this.getLogContent(logPrefix, startTime, message));
            logger.error(e.getMessage(), e);
        } catch (Exception e) {
            String message = "订单取消,通知商城失败,OrderCode:" + orderCode;
            logger.error(this.getLogContent(logPrefix, startTime, message));
            logger.error(e.getMessage(), e);
        }
        //更新Elasticsearch
        OrderHead esOrderHead = new OrderHead();
        esOrderHead.setOrderCode(orderCode);
        esOrderHead.setOrderStatus(this.getOrderStatus().getIndex());
        AsyncTaskHandler.executeAsyncTask(this.esProxy.newAsyncEditTask(EsProxy.transformToOrderHeadForEs(esOrderHead), logSign));
        //订单取消的标记（失效时间300s）
        OrderConcurrentHandler.setExpiredLock(orderCode);
        logger.info(this.getLogContent(logPrefix, startTime, "End"));
        commonResult = this.createResult(ReturnCode.REQUEST_SUCCESS, "取消处理成功");
        return commonResult;
    }

    private void updateHeadExt(Long orderCode, CancelOrderDto cancelOrderDto) {

        try {
            OrderHead head = orderQueryService.findByCode(orderCode, false, false);
            // TODO 2019-05-09
            OrderHeadExt headExt = new OrderHeadExt();
            headExt.setId(head.getId());
            headExt.setCancelTime(new Date());
            String cancelUser = cancelOrderDto.getCancelUser();
            String cancelRemark = cancelOrderDto.getCancelRemark();
            if (StringUtils.isNotEmpty(cancelUser)) {
                headExt.setCancelUser(cancelUser);
            }
            if (StringUtils.isNotEmpty(cancelRemark)) {
                headExt.setCancelRemark(cancelRemark);
            }

            this.orderUpdateService.updateOrderExt(headExt);
        } catch (Exception e) {
            logger.error(orderCode + " 订单取消设置headExt失败", e);
        }
    }


    private OrderHead findOrderHead(long orderCode) {
        OrderHead orderHead = this.orderQueryService.findByCode(orderCode, true, true);
        return orderHead;
    }

    private OrderHead findParentOrderHead(long orderCode) {
        OrderHead orderHead = this.orderQueryService.findByCodeAll(orderCode, false, false);
        return orderHead;
    }

    private CommonResult<Object> createResult(String code, String message) {
        CommonResult<Object> commonResult = new CommonResult<>(code, message);
        return commonResult;
    }

    private long getStartTime() {
        long startTime = System.currentTimeMillis();
        return startTime;
    }

    private String getLogContent(String prefix, long startTime, String message) {
        String content = this.logExecuteTime(prefix, startTime);

        StringBuilder sb = new StringBuilder();
        sb.append(content);
        if (!StringUtils.isBlank(message)) {
            sb.append("[").append(message).append("]");
        }
        return sb.toString();
    }

    private String logExecuteTime(String prefix, long startTime) {
        long endTime = System.currentTimeMillis();
        long executeTime = endTime - startTime;

        StringBuilder sb = new StringBuilder();
        sb.append(prefix).append("[").append(executeTime).append("ms]");
        return sb.toString();
    }

    private String getLogPrefix(String logSign) {
        StringBuilder sb = new StringBuilder();
        sb.append("[CancelOrder][").append(logSign).append("]");
        return sb.toString();
    }

    protected boolean checkOrderCode(Long orderCode) {
        boolean flag = false;
        if (orderCode != null) {
            flag = true;
        }
        return flag;
    }

    /**
     * 是否履约
     *
     * @param status
     * @return
     */
    protected boolean isFulfill(int status) {
        boolean flag = false;
        if (status >= OrderStatus.ORDER_WM_NEW.getIndex() && status <= OrderStatus.ORDER_WM_NEW.getIndex()) {
            flag = true;
        }

        return flag;
    }

    protected abstract boolean checkParams(CancelOrderDto cancelOrderDto);

    protected abstract boolean checkStatus(int status, int region);

    protected abstract CommonResult<Boolean> cancel(OrderHead orderHead, String logSign);

    protected abstract OrderOperateType getOperateType();

    protected abstract OrderStatus getOrderStatus();

    protected abstract boolean isForceCancel(OrderHead orderHead, String logSign);
}